﻿using System;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 具体处理各种定时任务操作的类
/// </summary>
public class Timer
{
    private readonly string obj = "lock";
    /// <summary>
    /// 输出的值为时间的起点1/1/0001 00:00:00
    /// </summary>
    private DateTime StartDataTime = new DateTime();
    /// <summary>
    /// 记录当前的时间
    /// </summary>
    private double NowTime;
    /// <summary>
    /// 当前定时任务的id号
    /// </summary>
    private int tid;
    /// <summary>
    /// tidLis的缓冲区
    /// </summary>
    private List<int> tidRec = new List<int>();
    private List<int> tidLis = new List<int>();
    /// <summary>
    /// TimerTasksList的缓存区
    /// </summary>
    private List<TimerTask> tempTimerTasks = new List<TimerTask>();
    private List<TimerTask> timerTasksList = new List<TimerTask>();

    public void Update()
    {
        TimerTaskUpdate();
        RecycleTid();
    }
    
    public int AddTimerTask(Action callBack,double delay,int doCount = 1,TimeUnit unit = TimeUnit.MS)
    {
        delay = ConvertUnit(delay, unit);
        NowTime = GetUtcMillis();
        tid = GetID();
        tidLis.Add(tid);
        //构造定时任务
        TimerTask timerTask = new TimerTask()
        {
            callback = callBack,
            delay = delay,
            doCount = doCount,
            tid = tid,
            desTime = NowTime + delay
        };
        tempTimerTasks.Add(timerTask);
        return tid;
    }
    public bool DelTimerTask(int tid)
    {
        bool exist = false;
        for (int i = 0; i < timerTasksList.Count; i++)
        {
            if (timerTasksList[i].tid == tid)
            {
                timerTasksList.RemoveAt(i);
                for (int j = 0; j < tidLis.Count; j++) 
                {
                    if (tidLis[j] == tid)
                    {
                        tidRec .Add( tid);
                        break;
                    }
                }
                exist = true;
                break;
            }
        }
        //如果没找到,去缓存区中再次找一下
        if (exist == false)
        {
            for (int i = 0; i < tempTimerTasks.Count; i++)
            {
                if (tempTimerTasks[i].tid == tid)
                {
                    tempTimerTasks.RemoveAt(i);
                    for (int j = 0; j < tidLis.Count; j++)
                    {
                        if (tidLis[i] == tid)
                        {
                            tidRec.Add(tid);
                            break;
                        }
                    }
                    exist = true;
                    break;
                }
            }
        }//如果到缓存区中还未找到
        if(exist == false)
        {
            Debug.Log("并没有找到当前tid的定时任务");
            return false;
        }
        return exist;
    }
    /// <summary>
    /// 将当前的定时任务替换为别的定时任务
    /// </summary>
    public bool ReplaceTimer(int tid, Action callBack, double delay, int doCount = 1, TimeUnit unit = TimeUnit.MS)
    {
        bool isReplaced = false;
        delay = ConvertUnit(delay,unit);
        NowTime = GetUtcMillis();
        TimerTask newTask = new TimerTask()
        {
            tid = tid,
            callback = callBack,
            delay= delay,
            doCount = doCount ,
            desTime = NowTime + delay 
        };
        for (int i = 0; i < timerTasksList.Count; i++)
        {
            if (timerTasksList[i].tid == newTask.tid)
            {
                //覆盖当前的任务
                timerTasksList[i] = newTask;
                isReplaced = true;
                break;
            }
        }
        //如果没找到,则在缓存区找
        if (isReplaced == false)
        {
            for (int i = 0; i < tempTimerTasks .Count; i++)
            {
                if (tempTimerTasks[i].tid == tid)
                {
                    tempTimerTasks[i] = newTask;
                    isReplaced = true;
                    break;
                }
            }
        } //如果在缓存区仍未找到,则直接返回false
        if (isReplaced == false) return false;
        return isReplaced;
    }

    private void TimerTaskUpdate()
    {
        for (int i = 0; i < tempTimerTasks.Count; i++)
        {
            timerTasksList.Add(tempTimerTasks[i]);
        }
        tempTimerTasks.Clear();
        NowTime = GetUtcMillis();
        for (int i = 0; i < timerTasksList.Count; i++)
        {
            TimerTask timerTask = timerTasksList[i];
            if (NowTime >= timerTask.desTime)//判断是否到了执行时间了
            {
                Action action = timerTask.callback;
                if (action != null) { action(); }
                else { Debug.Log("此定时任务并没有回调!"); }
                if (timerTask.doCount == 1)
                {
                    timerTasksList.Remove(timerTask);
                    i--;
                    tidRec.Add(timerTask.tid);
                }
                else//若为-1 表示无限执行此任务
                {
                    timerTask.doCount -= 1;
                    timerTask.desTime += timerTask.delay;
                }
            }
            else
            {
                continue;
            }
        }
    }
    /// <summary>
    /// 回收不用的Tid
    /// </summary>
    private void RecycleTid()
    {
        if (tidRec.Count > 0)
        {
            for (int i = 0; i < tidRec.Count; i++)
            {
                int tid = tidRec[i];
                for (int j = 0; j < tidLis.Count; j++)
                {
                    if (tid == tidLis[j])
                    {
                        tidLis.RemoveAt(j);
                        break;
                    }
                }
            }
        }
        tidRec.Clear();
    }
    /// <summary>
    /// 转换单位
    /// </summary>
    /// <param name="delay">延迟的时间</param>
    /// <param name="unit">单位</param>
    /// <returns>转换后的单位时间</returns>
    double ConvertUnit(double delay,TimeUnit unit)
    {
        double temp = delay;
        if (unit != TimeUnit.MS)
        {
            switch (unit)
            {
                case TimeUnit.S:
                    temp *= 1000;
                    break;
                case TimeUnit.M:
                    temp = temp * 1000 * 60;
                    break;
                case TimeUnit.H:
                    temp = temp * 1000 * 60 * 60;
                    break;
                case TimeUnit.D:
                    temp = temp * 1000 * 60 * 60 * 24;
                    break;
            }
        }
        return temp;
    }
    double GetUtcMillis()
    {
        TimeSpan span = DateTime.UtcNow - StartDataTime;
        return span.TotalMilliseconds;
    }
    int GetID()
    {
        lock (obj)
        {
            tid += 1;
            Judge();
        }
        return tid;
    }
    /// <summary>
    /// 处理id重复等安全校验
    /// </summary>
    void Judge()
    {
        while (true)
        {
            if (tid == Int32.MaxValue) tid = 0;
            bool isUse = false;
            for (int i = 0; i < tidLis.Count; i++)
            {
                //有重复id
                if (tid == tidLis[i])
                {
                    isUse = true;
                    tid++;
                }
                else
                {
                    isUse = false;
                    break;
                }
            }
            //当前id没有重复则退出校对
            if (isUse == false) break;
        }
    }
}